package com.ccl.iot.device;

import android.graphics.Bitmap;
import android.text.TextUtils;
import android.view.View;

import com.ccl.iot.IOTInterface;
import com.ccl.iot.IOTNetAPI;
import com.ccl.iot.IOTNetAPIEnum;
import com.ccl.iot.IOTObject;
import com.ccl.iot.dvr.utils.LogUtil;
import com.ccl.iot.huiju.IOTHuiJu;
import com.ccl.iot.huiju.MainActivity;
import com.ccl.iot.managers.DeviceManager;
import com.ccl.iot.managers.ImageManager;
import com.ccl.iot.object.IOTDeviceInfoEx;
import com.ccl.iot.object.IOTRegData;
import com.ccl.iot.privates.InfoProcessor;

import java.util.ArrayList;
import java.util.Arrays;


public abstract class IOTDevice implements IOTObject.IOTMultiListenObject,IOTHuiJu {

    public static final String KIOT_DEVICE_NAME_LABEL = "$D";
    public static final String KIOT_DEVICE_ICON_LABEL = "$I";

    /*
         * Static functions
         */
    protected static IOTNetAPI gNetAPI = IOTNetAPI.GetInstance();

    public static boolean IsRelativeDevice(IOTDevice aDevice, int aAddress, int aSize) {
        if (aDevice != null) {
            int tAddress, tSize;
            int tStartPos = 0;

            tAddress = aDevice.getRegisterAddress();
            tSize = aDevice.getRegisterSize();

            if (aAddress <= tAddress) {
                tStartPos = (tAddress - aAddress);

                if (aSize - tStartPos < tSize) {
                    return false;
                }
            } else {
                return false;
            }

            return true;
        }

        return false;
    }

    /*
     * Non-static functions
     */
    private long iID = 0;
    protected IOTDeviceInfoEx iDeviceInfo = null;    //设备信息
    private int iRegAddress = 0;    //设备寄存器地址
    private int iRegSize = 0;        //设备寄存器大小

    private String iHashCode = null;

    private boolean iOnline = false;

    private int iAuthState = IOTNetAPIEnum.EAUTH_STATE.EAUTH_STATE_UNKNOWN;        //账号对设备的权限
    private int iAuthStateNetWork = IOTNetAPIEnum.EIOT_NETWORK_TYPE.EIOT_NETWORK_TYPE_LOCAL;    //设备是否是本地的

    protected IOTRegisterInterface iRegisterInterface = null;    //寄存器接口

    protected int iImageCount = -1;        //拍照的图片数量
    protected String iDefaultImageID = null;    //默认图片id

    private int mNetWorkState = IOTNetAPIEnum.EIOT_NETWORK_TYPE.EIOT_NETWORK_TYPE_REMOTE;        //设备是否是本地的

    private boolean isSelected;

    protected int mDefIndex = 1;

    protected String mNameLabel;
    protected String mIconLabel;

    private String iDevSID = null;
    private String iDevIID = null;

    public boolean isSelected() {
        return isSelected;
    }

    public void setSelected(boolean mSelected) {
        isSelected = mSelected;
    }

    /**
     * 设置设备的网络状态(是否是本地的)
     *
     * @param state 网络状态
     */
    public void setNetWorkState(int state) {
        mNetWorkState = state;
    }

    /**
     * 获取设备网络状态
     *
     * @return
     */
    public int getNetWorkState() {
        return mNetWorkState;
    }

    public int getNetWorkState(View view) {
        return mNetWorkState;
    }

    public IOTDevice(long aDevID, IOTDeviceInfoEx aDeviceInfo, int aRegAddress, int aRegSize) {
        iID = aDevID;
        iDeviceInfo = aDeviceInfo;

        iRegAddress = aRegAddress;
        iRegSize = aRegSize;

        iHashCode = String.valueOf(getID());

        iDevSID = KIOT_DEVICE_NAME_LABEL + IOTNetAPI.GetStringID(getID());
        iDevIID = KIOT_DEVICE_ICON_LABEL + IOTNetAPI.GetStringID(getID());
    }

    public IOTDeviceInfoEx getDeviceInfo() {
        return iDeviceInfo;
    }

    public int getType() {
        if (iDeviceInfo != null) {
            return iDeviceInfo.iType;
        }

        return -1;
    }

    public String getUDID() {
        return iHashCode;
    }

    @Override
    public long getID() {
        return iID;
    }

    private ArrayList<IOTInterface.IOTNameMonitorInterface.IOTNameChangeListener> mNameChangeListeners = new ArrayList<>();
    private ArrayList<IOTInterface.IOTOnlineMonitorInterface.IOTOnlineStatusChangeListener> mOnlineChangeListeners = new ArrayList<>();
    private ArrayList<IOTInterface.IOTAuthMonitorInterface.IOTAuthChangeListener> mAuthChangeListeners = new ArrayList<>();
    private ArrayList<IOTInterface.IOTIconMonitorInterface.IOTIconChangeListener> mIconChangeListeners = new ArrayList<>();

    @Override
    public void addListener(IOTInterface.IOTListener aListener) {
        if (aListener != null) {
            if (aListener instanceof IOTNamedObject.IOTNameChangeListener) {
                this.addNameChangeListener((IOTInterface.IOTNameMonitorInterface.IOTNameChangeListener) aListener);
            } else if (aListener instanceof IOTOnlineObject.IOTOnlineStatusChangeListener) {
                this.addOnlineChangeListener((IOTInterface.IOTOnlineMonitorInterface.IOTOnlineStatusChangeListener) aListener);
            } else if (aListener instanceof IOTAuthObject.IOTAuthChangeListener) {
                this.addAuthChangeListener((IOTInterface.IOTAuthMonitorInterface.IOTAuthChangeListener) aListener);
            } else if (aListener instanceof IOTIcondObject.IOTIconChangeListener) {
                this.addIconChangeListener((IOTInterface.IOTIconMonitorInterface.IOTIconChangeListener) aListener);
            }
        }
    }

    @Override
    public void removeAllListeners(IOTInterface.IOTListener aListener) {
        if (aListener != null) {
            if (aListener instanceof IOTNamedObject.IOTNameChangeListener) {
                this.removeNameChangeListener((IOTInterface.IOTNameMonitorInterface.IOTNameChangeListener) aListener);
            } else if (aListener instanceof IOTOnlineObject.IOTOnlineStatusChangeListener) {
                this.removeOnlineChangeListener((IOTInterface.IOTOnlineMonitorInterface.IOTOnlineStatusChangeListener) aListener);
            } else if (aListener instanceof IOTAuthObject.IOTAuthChangeListener) {
                this.removeAuthChangeListener((IOTInterface.IOTAuthMonitorInterface.IOTAuthChangeListener) aListener);
            } else if (aListener instanceof IOTIcondObject.IOTIconChangeListener) {
                this.removeIconChangeListener((IOTInterface.IOTIconMonitorInterface.IOTIconChangeListener) aListener);
            }
        }
    }

    public String getNameLabel() {
        if (mNameLabel == null) {
            if (isOwner() || (!IOTNetAPIEnum.EAUTH_STATE.IS_READABLE(iAuthState) && !IOTNetAPIEnum.EAUTH_STATE.IS_WRITABLE(iAuthState))) {
                mNameLabel = KIOT_DEVICE_NAME_LABEL + "." + IOTNetAPI.GetStringID(mDefIndex);
            } else {
                mNameLabel = iDevSID + "." + IOTNetAPI.GetStringID(mDefIndex);
            }
        }
        return mNameLabel;
    }

    public String getIconLabel() {
        if (mIconLabel == null) {
            if (isOwner() || (!IOTNetAPIEnum.EAUTH_STATE.IS_READABLE(iAuthState) && !IOTNetAPIEnum.EAUTH_STATE.IS_WRITABLE(iAuthState))) {
                if (mDefIndex > 0) {
                    mIconLabel = KIOT_DEVICE_ICON_LABEL + "." + IOTNetAPI.GetStringID(mDefIndex);
                } else {
                    mIconLabel = KIOT_DEVICE_ICON_LABEL;
                }
            } else {
                if (mDefIndex > 0) {
                    mIconLabel = iDevIID + "." + IOTNetAPI.GetStringID(mDefIndex);
                } else {
                    mIconLabel = iDevIID;
                }
            }
        }
        return mIconLabel;
    }

    public boolean isNoName() {
        return TextUtils.isEmpty(InfoProcessor.getInstance().getInfo(getID(), getNameLabel(), isOwner()));
    }

    public boolean isNoIcon() {
        return TextUtils.isEmpty(InfoProcessor.getInstance().getInfo(getID(), getIconLabel(), isOwner()));
    }

    public String getName() {
        if (mName == null) {
            mName = InfoProcessor.getInstance().getInfo(getID(), getNameLabel(), isOwner());
            if (mName == null) {
                if (iDeviceInfo != null) {
                    mName = IOTNetAPI.GetStringID(getID()) + ":" + DeviceManager.GetDefaultManager().GetModel(iDeviceInfo.iModel, false) + "-" + (mDefIndex);
                } else {
                    mName = IOTNetAPI.GetStringID(getID());
                }
            }
        }

        return mName;
    }

    public String getIcon() {
        if (mIcon == null) {
            mIcon = InfoProcessor.getInstance().getInfo(getID(), getIconLabel(), isOwner());
            if (mIcon == null) {
                mIcon = "0";
            }

            int iconData = Integer.parseInt(mIcon);
            iconId = iconData & 0x00FFFFFF;
            mHide = (iconData >> 30) > 0;
        }

        return mIcon;
    }

    public void updateName(String name) {
        if (name != null) {
            if (!name.equals(mName)) {
                mName = name;
                onNameChange(mName);
            }
        }else{
            mName = null;
            getName();
            onNameChange(mName);
        }
    }

    public void updateIcon(String icon) {
        if (icon != null) {
            if (!icon.equals(mIcon)) {
                mIcon = icon;
                onIconChange(mIcon);
            }
        }else{
            mIcon = null;
            getIcon();
            onIconChange(mIcon);
        }
    }


    public boolean setName(String aName) {
        if (aName != null && !aName.equals(mName)) {
            String oldName = mName;
            mName = aName;
            onNameChange(mName);
            if (isOwner()) {
                InfoProcessor.getInstance().changeDevInfo(getID(), getNameLabel(), aName, oldName);
            } else {
                InfoProcessor.getInstance().changeUserInfo(getNameLabel(), aName, oldName);
            }
        }
        return true;
    }

    public boolean setIcon(String aIcon) {
        if (aIcon != null && !aIcon.equals(mIcon)) {
            String oldIcon = mIcon;
            mIcon = aIcon;
            onIconChange(mIcon);
            if (isOwner()) {
                InfoProcessor.getInstance().changeDevInfo(getID(), getIconLabel(), aIcon, oldIcon);
            } else {
                InfoProcessor.getInstance().changeUserInfo(getIconLabel(), aIcon, oldIcon);
            }
        }
        return true;
    }

    public void setIconId(int icon, boolean isSync) {
        if (isSync) {
            iconId = icon;
            onIconChange(mIcon);
            setIcon(icon + "");
        } else {
            mIcon = icon + "";
            onIconChange(mIcon);
        }
    }

    public boolean addNameChangeListener(IOTInterface.IOTNameMonitorInterface.IOTNameChangeListener aListener) {
        synchronized (mNameChangeListeners) {
            if (!mNameChangeListeners.contains(aListener)) {
                return mNameChangeListeners.add(aListener);
            }
            return false;
        }
    }

    public boolean addIconChangeListener(IOTInterface.IOTIconMonitorInterface.IOTIconChangeListener aListener) {
        synchronized (mIconChangeListeners) {
            if (!mIconChangeListeners.contains(aListener)) {
                return mIconChangeListeners.add(aListener);
            }
            return false;
        }
    }

    public boolean addOnlineChangeListener(IOTInterface.IOTOnlineMonitorInterface.IOTOnlineStatusChangeListener aListener) {
        synchronized (mOnlineChangeListeners) {
            if (!mOnlineChangeListeners.contains(aListener)) {
                return mOnlineChangeListeners.add(aListener);
            }
            return false;
        }
    }

    public boolean addAuthChangeListener(IOTInterface.IOTAuthMonitorInterface.IOTAuthChangeListener aListener) {
        synchronized (mAuthChangeListeners) {
            if (!mAuthChangeListeners.contains(aListener)) {
                return mAuthChangeListeners.add(aListener);
            }
            return false;
        }
    }

    public boolean removeNameChangeListener(IOTInterface.IOTNameMonitorInterface.IOTNameChangeListener aListener) {
        synchronized (mNameChangeListeners) {
            return mNameChangeListeners.remove(aListener);
        }
    }

    public boolean removeIconChangeListener(IOTInterface.IOTIconMonitorInterface.IOTIconChangeListener aListener) {
        synchronized (mIconChangeListeners) {
            return mIconChangeListeners.remove(aListener);
        }
    }

    public boolean removeOnlineChangeListener(IOTInterface.IOTOnlineMonitorInterface.IOTOnlineStatusChangeListener aListener) {
        synchronized (mOnlineChangeListeners) {
            return mOnlineChangeListeners.remove(aListener);
        }
    }

    public boolean removeAuthChangeListener(IOTInterface.IOTAuthMonitorInterface.IOTAuthChangeListener aListener) {
        synchronized (mAuthChangeListeners) {
            return mAuthChangeListeners.remove(aListener);
        }
    }

    public void onNameChange(String newName) {
        synchronized (mNameChangeListeners) {
            for (IOTInterface.IOTNameMonitorInterface.IOTNameChangeListener listener : mNameChangeListeners) {
                listener.onNameChanged(this, newName);
            }
        }
    }

    public void onIconChange(String newIcon) {
        if (!TextUtils.isEmpty(newIcon)) {
            int iconData = Integer.parseInt(newIcon);
            int newIconId = iconData & 0x00FFFFFF;
            boolean newHideState = (iconData >> 30) > 0;
            if (newHideState != mHide) {
                mHide = newHideState;
                if (mHideChangeListener != null) {
                    mHideChangeListener.onHideStateChange(newHideState);
                }
            }
            if (newIconId != iconId) {
                iconId = newIconId;
                synchronized (mIconChangeListeners) {
                    for (IOTInterface.IOTIconMonitorInterface.IOTIconChangeListener listener : mIconChangeListeners) {
                        listener.onIconChanged(this, newIcon);
                    }
                }
            }

        }
    }

    public void onOnlineChange(boolean online) {
        synchronized (mOnlineChangeListeners) {
            for (IOTInterface.IOTOnlineMonitorInterface.IOTOnlineStatusChangeListener listener : mOnlineChangeListeners) {
                listener.onOnlineStatusChanged(this, online);
            }
        }
    }

    public void onAuthChange(int newAuth) {
        synchronized (mAuthChangeListeners) {
            for (IOTInterface.IOTAuthMonitorInterface.IOTAuthChangeListener listener : mAuthChangeListeners) {
                listener.onAuthChanged(this, newAuth);
            }
        }
    }


    public boolean isOnline() {
        return iOnline;
    }

    public boolean setOnline(boolean aOnline) {
        if (iOnline != aOnline) {
            iOnline = aOnline;
            onOnlineChange(aOnline);

            return true;
        }

        return false;
    }

    public int getAuth() {
        return iAuthState;
    }

    public boolean setAuthState(int aNetWork, int aNewState) {
        if (iAuthState != aNewState) {
            if (iAuthStateNetWork == IOTNetAPIEnum.EIOT_NETWORK_TYPE.EIOT_NETWORK_TYPE_LOCAL || aNetWork == IOTNetAPIEnum.EIOT_NETWORK_TYPE.EIOT_NETWORK_TYPE_REMOTE
                    || gNetAPI.isRemoteReady() == false) {
                iAuthState = aNewState;
                iAuthStateNetWork = aNetWork;
                //                LoggerUtil.e("network","network:" + aNetWork);

                onAuthChange(aNewState);

                return true;
            }
        }

        return false;
    }

    public boolean setAuth(int aAuthState) {
        return setAuthState(IOTNetAPIEnum.EIOT_NETWORK_TYPE.EIOT_NETWORK_TYPE_LOCAL, aAuthState);
    }

    public void setRegisterInterface(IOTRegisterInterface aInterface) {
        iRegisterInterface = aInterface;
    }

    public boolean isOwner() {
        return iAuthState == IOTNetAPIEnum.EAUTH_STATE.EAUTH_STATE_OWNER;
    }

    public boolean isReadable() {
        return IOTNetAPIEnum.EAUTH_STATE.IS_READABLE(iAuthState);
    }

    public boolean isWritable() {
        return IOTNetAPIEnum.EAUTH_STATE.IS_WRITABLE(iAuthState);
    }

    public int getRegisterAddress() {
        return iRegAddress;
    }

    private IOTRegData mRegData;
    protected void saveRegister(int iRegAddress, int aSize, byte aData[], int aNetWork){
        if(aNetWork != IOTNetAPIEnum.EIOT_NETWORK_TYPE.EIOT_NETWORK_TYPE_LOCAL){
            if(mRegData == null){
                mRegData = new IOTRegData();
            }
            mRegData.iAddress = iRegAddress;
            mRegData.iData = aData;
            mRegData.iSize = aSize;
        }
    }

    public String getSaveString(){

        if(mRegData != null && iDeviceInfo != null){
            return "{\"aData\":"+ Arrays.toString(mRegData.iData)+",\"aSize\":"+mRegData.iSize+",\"iAddress\":"+mRegData.iAddress+",\"iAuthState\":"+iAuthState+",\"iID\":"+iID
                    +",\"iModel\":"+iDeviceInfo.iModel+",\"iOnline\":"+iOnline+",\"iRegisterSpace\":"+iDeviceInfo.iRegisterSpace
                    +",\"iType\":"+iDeviceInfo.iType+",\"iVersion\":"+iDeviceInfo.iVersion+"}";
        }

        return null;
    }

    public final int getRegisterSize() {
        return iRegSize;
    }

    public abstract byte[] getRegister();

    public abstract void updateRegister(int aAddress, int aSize, byte aData[], int aDataPos, int aNetWork, long time);

    public abstract String getStateID();

    public abstract String[] getStateIDs();

    @Override
    public String toString() {
        return "Device:" + getName() + ", " + getDeviceInfo().toString();
    }

    /*
     * Device image part
     */
    public String getImageID(String aID) {
        return "DEV." + getUDID() + "." + aID;
    }

    public int getImageId() {
        return 0;
    }

    public void onViewClick() {

    }

    public int getImageCount() {
        if (iImageCount == -1) {
            String tIDs[] = getStateIDs();

            iImageCount = 0;
            if (tIDs != null) {
                for (int i = 0; i < tIDs.length; i++) {
                    if (ImageManager.ContainsBitmap(getImageID(tIDs[i]))) {
                        iImageCount++;
                    }
                }
            }
        }

        return iImageCount;
    }

    public String getImageID(String aID, boolean aAutoID) {
        if (aAutoID && iImageCount == 1) {
            aID = iDefaultImageID;
        }

        return "DEV." + getUDID() + "." + aID;
    }

    public boolean setImage(Bitmap aImage) {
        String tID = getImageID(getStateID());

        getImageCount();

        if (aImage == null) {
            if (ImageManager.RemoveBitmap(tID)) {
                iImageCount--;
                return true;
            }
        } else {
            boolean tOld = ImageManager.ContainsBitmap(getImageID(getStateID()));

            if (ImageManager.SetBitmap(tID, aImage)) {
                if (tOld == false) {
                    iImageCount++;
                }

                return true;
            }
        }

        return false;
    }

    public Bitmap getImage() {
        if (getImageCount() > 0) {
            String tID = getImageID(getStateID());

            Bitmap tBitmap = ImageManager.GetBitmap(tID);

            if (tBitmap == null) {
                String tIDs[] = getStateIDs();

                if (tIDs != null) {
                    for (int i = 0; i < tIDs.length; i++) {
                        if ((tBitmap = ImageManager.GetBitmap(getImageID(tIDs[i]))) != null) {
                            break;
                        }
                    }
                }
            }

            return tBitmap;
        }

        return null;
    }

    //===========================modify start==============================

    private boolean mUpgradeable = false;
    private boolean mReupgradeable = false;
    private boolean mHide = false;
    private boolean mHideable = false;
    private boolean mRestoreable = false;
    private String mRomUpgradeInfo = null;
    private int iconId = 0;

    protected String mName = null;
    protected String mIcon = null;

    public boolean isUpgradeable() {
        return mUpgradeable;
    }

    public boolean isReupgradeable() {
        return mReupgradeable;
    }

    public void setUpgradeable(boolean upgradeable) {
        mUpgradeable = upgradeable;
    }

    public void setReupgradeable(boolean upgradeable) {
        mReupgradeable = upgradeable;
    }

    public void setRomUpgradeInfo(String info) {
        mRomUpgradeInfo = info;
    }

    public String getRomUpgradeInfo() {
        return mRomUpgradeInfo;
    }

    public int getSplitIconId() {
        getIcon();
        return iconId;
    }

    public int getNoSplitIconData() {
        if (!TextUtils.isEmpty(mIcon)) {
            return Integer.parseInt(mIcon);
        }
        return 0;
    }

    public int getNoSplitIconId() {
        if (!TextUtils.isEmpty(mIcon)) {
            return Integer.parseInt(mIcon);
        }
        return 0;
    }

    public boolean isHide() {
        return mHide;
    }

    public void setHide(boolean hide) {
        if (mHide != hide) {
            if (hide) {
                iconId = iconId | 0x40000000;
            } else {
                iconId = iconId & 0xff;
            }
            setIconId(iconId, true);
        }
    }

    public boolean getHideable() {
        return mHideable;
    }

    public void setHideable(boolean hideable) {
        mHideable = hideable;
    }

    public boolean getRestoreable() {
        return mRestoreable;
    }

    public void setRestoreable(boolean restoreable) {
        mRestoreable = restoreable;
    }

    public void restoreOuther() {
        if (mHideChangeListener != null) {
            mHideChangeListener.retoreOuther();
        }
    }

    private OnHideRestoreListener mHideChangeListener;

    public void setOnHideRestoreListener(OnHideRestoreListener listener) {
        mHideChangeListener = listener;
    }

    protected int mOldId = 0;

    public void resetIconId() {
        iconId = mOldId;
    }

    public void revalidIconId() {
    }

    //===========================modify end==============================


    private int mPositionIndex = -1;
    private int mPageIndex = -1;

    public int getPositionIndex() {
        return mPositionIndex;
    }

    public void setPositionIndex(int positionIndex) {
        mPositionIndex = positionIndex;
    }

    public int getPageIndex() {
        return mPageIndex;
    }

    public void setPageIndex(int pageIndex) {
        mPageIndex = pageIndex;
    }

    public void writeRegister(int aAddress, int aSize, byte aData[], int netWorkState){
        LogUtil.i(MainActivity.TAG,"writeRegister:" + aAddress + ", " + aSize + ", "
                + Arrays.toString(Arrays.copyOf(aData, aSize)));
        iRegisterInterface.writeRegister(this, aAddress, aSize, aData, netWorkState);
    }

}
